#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>

#define POOL_NUM 10

/*
    任务队列里的一个任务节点（用于组成一个任务队列这个链表）
*/
typedef struct Task{
    void *arg;
    void *(*func)(void *arg);
    struct Task *next;
}Task_t;

/*
    线程池
*/
typedef struct ThreadPool{
    pthread_mutex_t task_lock;
    pthread_cond_t new_task;
    pthread_t tid[POOL_NUM];
    
    Task_t *Task_Head;
    int BusyWork;
}ThreadPool_t;

ThreadPool_t *pool = NULL;

/*
    一个任务真正要干的活
*/
void *Real_Work(void *arg)
{
    printf("Finish work %d\n", (int)arg);
}

/*
    线程池添加任务

    	判断是否有空闲的工作线程
        给任务队列添加一个节点
        给工作线程发送信号newtask
*/
void Pool_Add_Task(int arg)
{
    /************************************************************************/
    /* 这一段代码是为了防止任务丢失的问题 */
    pthread_mutex_lock(&pool->task_lock);   //操作临界资源必须加锁
    if(pool->BusyWork >= POOL_NUM)
    {
        pthread_mutex_unlock(&pool->task_lock);
        usleep(10000);
        pthread_mutex_lock(&pool->task_lock);
    }
    pthread_mutex_unlock(&pool->task_lock);
    /************************************************************************/

    Task_t *new_node = malloc(sizeof(Task_t));
    new_node->arg = arg;
    new_node->func = Real_Work;     //这里只是对函数指针初始化，还没有真实执行Real_work

    //往任务队列里插入任务
    pthread_mutex_lock(&pool->task_lock);
    if(pool->Task_Head == NULL) 
    {
        pool->Task_Head = new_node;     //如果这是第一个任务，就把新任务插在任务队列的头部
    }
    else
    {
        Task_t *Task_Tail = pool->Task_Head;

        /* 如果这不是第一个任务，就把新任务插在任务队列的尾部 */
        while(Task_Tail->next != NULL)
        {
            Task_Tail = Task_Tail->next;  //遍历到链表的尾部
        }
        Task_Tail->next = new_node;//***********************************************************************************************************

    }
    pool->BusyWork++;
    pthread_cond_signal(&pool->new_task);

    pthread_mutex_unlock(&pool->task_lock);
}

/*
    工作线程
*/
void *Work_Thread(void *arg)
{
    pthread_detach(pthread_self());
    while(1)
    {
        pthread_mutex_lock(&pool->task_lock);
        pthread_cond_wait(&pool->new_task, &pool->task_lock);

        Task_t *ptask = pool->Task_Head;    //收到信号，取出任务
        pool->Task_Head = pool->Task_Head->next;    //任务队列的头部下移一个节点

        pthread_mutex_unlock(&pool->task_lock);

        ptask->func(ptask->arg);    //这里才真实执行了Real_Work
        pool->BusyWork--;
    }
}

/*
    创建一个线程池结构
    实现任务队列互斥锁和条件变量的初始化
    创建n个工作线程
*/
void Pool_Init(void)
{
    pool = malloc(sizeof(ThreadPool_t));   //第一步，分配空间

    /* 动态初始化条件变量和互斥锁 */
    pthread_mutex_init(&pool->task_lock, NULL);
    pthread_cond_init(&pool->new_task, NULL);
    pool->Task_Head = NULL;
    pool->BusyWork = 0;

    for(int i = 0;i < POOL_NUM; i++)
    {
        pthread_create(&pool->tid[i], NULL, Work_Thread, NULL);
    }
    
}

/*
    线程的销毁
*/
void pool_destory(void)
{
    Task_t *temp;

    /* 销毁链表 */
    while(pool->Task_Head != 0)
    {
        temp = pool->Task_Head;
        pool->Task_Head = pool->Task_Head->next;
        free(temp);
        temp = NULL;
    }

    pthread_mutex_destroy(&pool->task_lock);
    pthread_cond_destroy(&pool->new_task);
    free(pool);
}



int main(void)
{
    Pool_Init();
    sleep(1);
    int i;

    /* 假设有10个任务需要解决 */
    for(i = 1;i <= 20; i++)
    {
        Pool_Add_Task(i);
    }

    sleep(2);
    pool_destory();


    return 0;
}
